python

您所在的位置:网站首页 pyechart 热力图标记线 python

python

2024-07-13 01:49| 来源: 网络整理| 查看: 265

问题描述

昨天一直在搞pyecharts绘图和输出,网上搜了不少,坑太多了。。。最终我绘图的结果如下: 在这里插入图片描述 遇到的难点:(下面会逐一给出解法!完整代码涉及隐私,恕不提供!有问题请留言讨论)

x轴和y轴的名称需要修改位置、字体、颜色更改线条属性(颜色、宽度等)x轴横坐标最小值与原点重合y轴的刻度需要自定义+控制格式x轴和y轴的副刻度需要自定义曲线顶点处需要放置文字+控制格式需要输出pdf 环境

win10 + Python 3.9.12 + pyecharts 1.9.1 + snapshot_phantomjs 0.0.3

解决方案

以下直接略过数据准备阶段。已知 x_list是x的值列表,pts_list是y的值列表。

整体结构

代码的整体结构如下:

from pyecharts.charts import Line, Grid from pyecharts import options as opts from pyecharts.commons.utils import JsCode def draw(file_name): # 准备数据 x_list:list[str], pts_list:list[float] # x_list2 = [""] * (len(x_list)-1) # 绘制折线 line = ( # 整体初始化,如图像宽、高,背景颜色等 Line(init_opts=opts.InitOpts(height="600px", bg_color='rgb(255, 255, 255)')) # x轴数据 .add_xaxis(x_list) # y的数据、线的颜色、点的形状等 .add_yaxis(pts_list) .set_global_opts( # x轴上的文字,如x轴名称、范围、对齐方式、与轴的距离、字体颜色等 xaxis_opts=opts.AxisOpts(), # y轴同理 yaxis_opts=opts.AxisOpts(), # 设置图上的文字附注 graphic_opts=[ opts.GraphicText( # 设置位置、旋转方向等 graphic_item=opts.GraphicItem(), # 设置字号、颜色、字体、内容等 graphic_textstyle_opts=opts.GraphicTextStyleOpts(), ), ], ) ) # 绘制副刻度:没有放数值,只是为了画刻度 line2 = (Line() .add_xaxis(x_list2) .set_global_opts( xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts()), yaxis_opts=opts.AxisOpts(), ) ) # 这里为了将两部分组合起来 grid = Grid() # pos_left是左侧的边距,也就是将图向右移动一些。同理还有pos_left pos_top等 grid.add(line, grid_opts=opts.GridOpts(pos_left='12%')) grid.add(line2, grid_opts=opts.GridOpts(pos_left='12%')) # 保存为html文件 #grid.render("html/" + file_name + ".html") # # 也可以用phantomjs另存为图像或pdf,后文会介绍 # from pyecharts.render import make_snapshot # from snapshot_phantomjs import snapshot #make_snapshot(snapshot, grid.render(), "pdf/" + file_name + ".pdf") #make_snapshot(snapshot, grid.render(), "pdf/" + file_name + ".png") x轴和y轴的名称需要修改位置、字体、颜色

下面以x轴举例。y轴是差不多的。

.set_global_opts( xaxis_opts=opts.AxisOpts( # 坐标轴名称 name="xxx", # 最小值 min_=x_list[0], # 最大值 max_=x_list[-1], # 是否将最小值与原点重合。如果是True的话,最小值跟原点之间会有距离 boundary_gap=False, # 水平对齐。y轴的应该写middle,就是竖着居中了 name_location='center', # 名称与轴之间的距离 name_gap=30, # 坐标轴名字的格式 name_textstyle_opts=opts.TextStyleOpts( color='navy', font_family='Courier New', font_size=15, ), # 刻度值的格式。此处是主刻度,interval表示隔x个显示一个刻度值 axislabel_opts=opts.LabelOpts( color='navy', font_size=15, font_family='Courier New', interval=299, ),

颜色不止可以使用navy,red之类的,也可以传递rgb值。

linestyle_opts=opts.LineStyleOpts(color='#0000CC') 更改线条属性(颜色、宽度等) .add_yaxis(y_axis=pts_list,series_name="", is_symbol_show=False, # 去掉线上的圆圈 linestyle_opts=opts.LineStyleOpts(color="red", width=0.7), # 设置线条格式 label_opts=opts.LabelOpts(is_show=False), )

如果想搞成阶梯式的线条,可以加:

is_step=True,

设置好之后如下图所示: 在这里插入图片描述

x轴横坐标最小值与原点重合 boundary_gap=False,

参见上上节。

y轴的刻度需要自定义+控制格式 # 刻度值 axislabel_opts=opts.LabelOpts( # 文本格式控制 color='navy', font_size=15, font_family='Courier New', #formatter="{value}E+00" + postfix, # postfix是一个str类型变量 formatter=JsCode( ''' function(value){ if (value == '0') { return '0.0E+000'; } else { return value + 'E+00' + 'TAIL'; } }'''.replace('TAIL', postfix) ), ),

这里要说明一下formatter。JsCode实际是一段字符串,value表示的是某个刻度的值,是字符串类型,可以用console.log打出来看看。 怎么传递变量进去,我真的没搞懂,但是,用另一个常量代替待传递变量,然后replace掉,是可以实现我要的效果的。

2022/11/6更新:JsCode控制坐标轴标签实例-以科学计数法显示刻度值

使用正则表达式控制格式。其实就是javascript,稍微改一下就行(但是一些js的函数不能用,我不懂为什么)

formatter=JsCode( ''' function(value){ var p1=/[1-9][.][1-9][E]/g; var p2=/0[.][1-9][E]/g; if (value == '0') { return '0.0E+000'; } else { var s = value + 'E'; if(s.match(p1)){ return value + 'E+00' + 'TAIL'; } else if(s.match(p2)){ return s.substr(2,1) + '.0E+00' + 'MIN'; } else { console.log(s); return value + '.0E+00' + 'TAIL'; } } }'''.replace('TAIL', str(index_y)).replace('MIN', str(index_y-1)) ), x轴和y轴的副刻度需要自定义

因为line1的坐标轴刻度是跟着数据走的,为了多加一套副刻度,所以我另外写了一个line2,只用来控制副刻度,然后再把line1和line2叠加起来。这里副刻度需要控制的是interval。

line2 = (Line() .add_xaxis(x_list2) .set_global_opts( ... yaxis_opts=opts.AxisOpts( max_=max_y, min_=0.0, # y_step是主刻度的interval值 interval=y_step/ 4, # 只显示刻度,不显示标签 axislabel_opts=opts.LabelOpts( color='transparent', font_size=15, font_family='Courier New', ), # 设置刻度颜色 axisline_opts=opts.AxisLineOpts(linestyle_opts=opts.LineStyleOpts(color='navy')), ), ) ) 曲线顶点处需要放置文字+控制格式 graphic_opts=[ opts.GraphicText( # 修改位置和旋转角度。注意rotation用的是弧度,不是角度 graphic_item=opts.GraphicItem(position=(455,40),rotation=0.5*pi), graphic_textstyle_opts=opts.GraphicTextStyleOpts( text=str(num), # 这个num是我自定义的变量 font='12px "Courier New"', # 字号和字体 # 文字颜色 graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(fill='navy') ), ), ],

在搜索时,我一开始没去看官方文档,结果font那里少了font-family外的引号,导致设置失败。 一定要去看官方文档!!!官方说的很清楚,font-family要用引号括起来。

输出pdf

先上结论:使用pyecharts推荐的phantomjs是最好的。 不过,这种方法生成的pdf只有图像,没办法调节边距、图纸方向和大小等,一种解决方案是使用毒霸PDF转换器-图片转PDF,可以批量转换(测试时,200个png转pdf在3分钟以内完成)。当然,也有很多工具可以使用。 在这里插入图片描述 代码:

from pyecharts.render import make_snapshot from snapshot_phantomjs import snapshot # grid存放了一些图像 make_snapshot(snapshot, grid.render(), "pdf/" + file_name + ".pdf") make_snapshot(snapshot, grid.render(), "pdf/" + file_name + ".png")

除了需要pip安装一下snapshot_phantomjs外,还需要下载一下phantomjs-2.1.1-windows,将下图这个的路径放入系统环境变量Path,就是让程序调用时可以找到它。 在这里插入图片描述

加快make_snapshot的速度

这里尝试了改国内源,但是,在输出的png图像中,有相当一部分丢失了图像的细节(比如刻度少了或者没有线条),个人不是很懂是什么原理,而且使用国内源速度并无明显提升(可能打开html时会更快,但对打png的速度没啥影响)。以后有时间再研究这个问题吧。

from pyecharts.globals import CurrentConfig # 然后在绘图前加入: CurrentConfig.ONLINE_HOST = "https://cdn.jsdelivr.net/npm/echarts@latest/dist/"

之后可以去看打出的html源代码(顶部引用资源处),已经改为国内源的了。

html输出为pdf

另外,我还尝试了一些包,但是在将html打印为pdf时会出现以下几种情况:

打印出的pdf是空白的能打印出坐标轴,但没有折线图像

这些包在打印标准格式的html时是ok的,所以下面将列出代码存档备用。

下面的包都是在anaconda中使用pip安装的,如果有问题自行搜素。

weasyprint from weasyprint import HTML HTML("7024.html").write_pdf("7024.pdf")

如果遇到找不到cairo/cairo2之类的库,很可能是因为没装gtk,装一个gtk2或者gtk3即可解决。

pdf_reports

https://github.com/Edinburgh-Genome-Foundry/pdf_reports/blob/master 这个包其实是基于weasyprint的。

from pdf_reports import write_report write_report("html/7024.html", "example.pdf") PyQt5

印象中这个是打印不出折线图像。坐标轴和文字附注是能打印出来的。

from PyQt5.QtWidgets import QApplication from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets from PyQt5.QtCore import QMarginsF from PyQt5.QtPrintSupport import QPrinter from PyQt5.QtGui import QPageLayout, QPageSize import sys app = QtWidgets.QApplication(sys.argv) loader = QtWebEngineWidgets.QWebEngineView() loader.load(QtCore.QUrl('file:///本地地址/7024.html')) layout = QPageLayout( QPageSize(QPageSize.A4), QPageLayout.Portrait, QMarginsF(0, 0, 0, 0) ) def printFinished(): page = loader.page() print("%s Printing Finished!" % page.title()) app.exit() def printToPDF(finished): loader.show() time.sleep(60) page = loader.page() page.printToPdf("E:\pdf%s.pdf" % page.title(), layout) loader.page().pdfPrintingFinished.connect(printFinished) loader.loadFinished.connect(printToPDF) app.exec_() pdfkit

下载wkhtmltopdf,然后放到系统环境变量Path。 https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_msvc2015-win64.exe

import pdfkit pdfkit.from_file('test.html', 'out.pdf')


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3